package ui.server;
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

import java.io.*;
import java.net.SocketException;

import util.FileTransferConfig;
import util.IEventCallback;
import util.IOUtil;
import util.MessageInfo;


public class JFileTransferServerApp extends JFrame 
								implements ActionListener {
	
	private FileTransferServer server;
	private FileTransferConfig config;
	static private final String newline = "\n";
	
	private JTextField txTargetDir;
	private JTextField txServerPort;
	private JButton btnChooseDst;
	private JButton btnStartServer;
	private JTextArea taServerLog;
	private JTabbedPane tabPanel;
	private JFileTree tree;
	private IOUtil ioUtil;
	
	public JFileTransferServerApp() { 
	    super("File Transfer Server");
	    
	    // load config
	    try {
			config = new FileTransferConfig();
		} catch (IOException e) {
			e.printStackTrace();
		}
		// initial UI
	    initUIComponents(); 
	} 
	
	private void initUIComponents() {
		tabPanel = new JTabbedPane();
		getContentPane().add(tabPanel, BorderLayout.CENTER);;
		initServerUI();
	}
	
	private void initServerUI() {
		JPanel panelServer = new JPanel();
		tabPanel.addTab("Server", null, panelServer, null);
		panelServer.setLayout(new BorderLayout());
		
		JPanel panelSettingNetwork = new JPanel();
		panelServer.add(panelSettingNetwork, BorderLayout.NORTH);
		panelSettingNetwork.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		
		JLabel labHost = new JLabel("Port:");
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0.25;
		c.gridx = 0;
		c.gridy = 0;
		c.insets = new Insets(2, 2, 2, 2);
		panelSettingNetwork.add(labHost, c);
		
		txServerPort = new JTextField(config.serverport);
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 1.0;
		c.gridx = 1;
		c.gridy = 0;
		panelSettingNetwork.add(txServerPort, c);
		
		btnStartServer = new JButton("Start");
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0.25;
		c.gridx = 2;
		c.gridy = 0;
		btnStartServer.addActionListener(this);
		btnStartServer.setActionCommand(IOUtil.CMD_SERVER_START);
		panelSettingNetwork.add(btnStartServer, c);
		
		JLabel labFile = new JLabel("File:");
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0.25;
		c.gridx = 0;
		c.gridy = 1;
		panelSettingNetwork.add(labFile, c);
		
		txTargetDir = new JTextField(config.serverdir);
		txTargetDir.setEditable(false);
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 1.0;
		c.gridx = 1;
		c.gridy = 1;
		panelSettingNetwork.add(txTargetDir, c);
		
				
		btnChooseDst = new JButton("Browse");
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0.25;
		c.gridx = 2;
		c.gridy = 1;
		btnChooseDst.addActionListener(this);
		btnChooseDst.setActionCommand(IOUtil.CMD_SERVER_CHOOSE_DIR);
		panelSettingNetwork.add(btnChooseDst, c);
				
		// Jtree
		tree = new JFileTree(new File(config.serverdir));
		panelServer.add(tree, BorderLayout.CENTER);
		
		// log panel
	    taServerLog = new JTextArea(5,20);
        taServerLog.setMargin(new Insets(5,5,5,5));
        taServerLog.setEditable(false);
        JScrollPane logScrollPane = new JScrollPane(taServerLog);
        panelServer.add(logScrollPane, BorderLayout.SOUTH);
	 
        ioUtil = new IOUtil(taServerLog);
	}
	    
    private void updateObjState(String object, boolean state)
    {
    	if(object.equalsIgnoreCase("server_stop")) {
    		if(state)
    			btnStartServer.setText("Stop");
    		else
    			btnStartServer.setText("Start");
    	}
    }
    
        
    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from
     * the event dispatch thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
    	JFrame frame = new JFileTransferServerApp();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        		
		// Add content to the window
		frame.pack();
		frame.setLocation(200,200);
		frame.setSize(800,450);
		frame.setVisible(true);
		
    }
    
	public static void main(String args[]) {
		//Schedule a job for the event dispatch thread:
        //creating and showing this application's GUI.
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                //Turn off metal's use of bold fonts
            	UIManager.put("swing.boldMetal", Boolean.TRUE);
            	createAndShowGUI();
            }
        });
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equalsIgnoreCase(IOUtil.CMD_SERVER_CHOOSE_DIR)) {
			JFileChooser fc = new JFileChooser(this.txTargetDir.getText());
			fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			int returnVal = fc.showOpenDialog(this);

            if (returnVal == JFileChooser.APPROVE_OPTION) {
                File file = fc.getSelectedFile();
                txTargetDir.setText(file.getAbsolutePath()); 
                config.serverdir = txTargetDir.getText();
                tree.reload(new File(config.serverdir));
                ioUtil.dumpInfoMsg("Opening: " + file.getAbsolutePath() + ".");
                
            } else {
            	ioUtil.dumpInfoMsg("Open command cancelled by user.");
            	
            }
		}
		
		else if (e.getActionCommand().equalsIgnoreCase(IOUtil.CMD_SERVER_START)) {
			ioUtil.dumpInfoMsg("Get action command:" + e.getActionCommand());
			try {
				config.serverport = txServerPort.getText();
				config.serverdir = txTargetDir.getText();
				config.setConfig();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
			if(server == null)
			{
				server = new FileTransferServer(Integer.valueOf(config.serverport), config.serverdir);
				server.setCallback(this);
				ioUtil.dumpInfoMsg("Create file transfer server.");
			}

			new Thread(new Runnable(){ 
            	public void run() { 
            		try {
            			ioUtil.dumpInfoMsg("Start file transfer server.");
						server.startServer();
					} catch (SocketException ex) {
						ioUtil.dumpServerMsg("[ERROR][SocketException]: " + ex.getMessage());
					}
            		catch (IOException ex) {
            			ioUtil.dumpServerMsg("[ERROR][IOException]: " + ex.getMessage());
					}
            		
            }}).start();
			
			btnStartServer.setActionCommand(IOUtil.CMD_SERVER_STOP);
			
		}
		else if (e.getActionCommand().equalsIgnoreCase(IOUtil.CMD_SERVER_STOP)) {
			System.out.println("[actionPerformed]" + IOUtil.CMD_SERVER_STOP);
			if(server != null)
			{
				try {
					ioUtil.dumpInfoMsg("Stop file transfer server.");
					server.stopServer();
				} catch (SocketException ex) {
					ioUtil.dumpServerMsg("[ERROR][SocketException]: " + ex.getMessage());
				} catch (IOException ex) {
					ioUtil.dumpServerMsg("[ERROR][IOException]: " + ex.getMessage());
				} catch (Exception ex) {
					ex.printStackTrace();
					ioUtil.dumpServerMsg("[ERROR][Exception]: " + ex.getMessage());
				}
			}
			btnStartServer.setActionCommand(IOUtil.CMD_SERVER_START);
		}
	}
	public void doErrCallback(String event, String errMessage, long...argv) 
	{
		StringBuffer buffer  = new StringBuffer();
		buffer.append("[ERROR]");
		if(argv.length > 0) {
			if (argv[0] == IEventCallback.ERR_IO_EXCEPTION) {
				buffer.append("[IOException]: ");
			}
			else if (argv[0] == IEventCallback.ERR_SOCKET_EXCEPTION) {
				buffer.append("[SocketException]: ");
			}
		}
		buffer.append(errMessage);
		ioUtil.dumpServerMsg(buffer.toString());
	}
	
	public void doEvtCallback(String event, long... argv)
	{
		StringBuffer message = new StringBuffer();
		for(int i = 0; i < argv.length; i++)
		{
			if (i == 0) {
				long evt = argv[0];
				if (evt == IEventCallback.EVT_SERVER_RECV_FILE_PROGRESS) {
					message.append("EVT_SERVER_RECV_FILE_PROGRESS");
				}
				else if (evt == IEventCallback.EVT_SERVER_RECV_FILE_COMPLETE) {
					message.append("EVT_SERVER_RECV_FILE_COMPLETE");
				}
				else if (evt == IEventCallback.EVT_SERVER_CONN_START) {
					message.append("EVT_SERVER_CONN_START");
				}
				else if (evt == IEventCallback.EVT_SERVER_CONN_CLOSE) {
					message.append("EVT_SERVER_CONN_CLOSE");
				}
				else if (evt == IEventCallback.EVT_SERVER_RECV_FILE_START) {
					message.append("EVT_SERVER_RECV_FILE_START");
				}
				else {
					message.append(String.valueOf(evt));
				}
			}
			else {
				message.append(", " + String.valueOf(argv[i]));
			}
		}
		
		if(event.equalsIgnoreCase(IEventCallback.CALLBACK_TYPE_SERVER))
		{
			if(argv.length > 0) {
				if ( argv[0] == IEventCallback.EVT_SERVER_RECV_FILE_COMPLETE ) {
					tree.reload(new File(config.serverdir));
				}
				else if (argv[0] == IEventCallback.EVT_SERVER_CONN_START) {
					updateObjState("server_stop", true);
				}
				else if (argv[0] == IEventCallback.EVT_SERVER_CONN_CLOSE) {
					updateObjState("server_stop", false);
				}
			}
			if (argv[0] < IEventCallback.EVT_SERVER_RECV_FILE_START) {
				ioUtil.dumpClientMsg(message.toString());
			}
			else {
				ioUtil.dumpServerMsg(message.toString());
			}
		}
	}
}



